package com.ylr.admin.framework.service.impl;

import com.ylr.admin.framework.entity.RoleUriEntity;
import com.ylr.admin.framework.entity.UriEntity;
import com.ylr.admin.framework.mapper.RoleUriMapper;
import com.ylr.admin.framework.service.RoleUriService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylr.base.common.enums.CommonEnum;
import com.ylr.base.common.po.user.UserPo;
import com.ylr.base.common.utils.ThrottleUtils;
import com.ylr.base.common.utils.UserUtils;
import com.ylr.base.framework.service.AsyncService;
import com.ylr.base.framework.service.SnowflakeService;
import com.ylr.config.framework.resolver.YcMappingResolver;
import com.ylr.redis.framework.service.RedisService;
import com.ylr.redis.framework.service.RedisStringService;
import com.ylr.redis.framework.service.RedissonService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-21 11:45:00
 * className: RoleUriServiceImpl
 * version: 1.0
 * description:
 */
@Service("roleUriService")
@AllArgsConstructor
public class RoleUriServiceImpl extends ServiceImpl<RoleUriMapper, RoleUriEntity> implements RoleUriService {

    private static final Logger log = LoggerFactory.getLogger(RoleUriServiceImpl.class);

    private final YcMappingResolver ycMappingResolver;

    private final SnowflakeService snowflakeService;

    private final AsyncService asyncService;

    private final RedisStringService redisStringService;

    private final RedisService redisService;

    private final RedissonService redissonService;

    private final ThrottleUtils throttleUtils;

    @Transactional
    @Override
    public void saveOrUpdateRoleUri(Long roleId, List<Long> uriIdList) {
        // 获取正在保存角色关联系统接口数据的用户
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        // 查询角色已关联的系统接口主键集合
        Set<Long> uriIdSet = baseMapper.findUriIdSet(roleId, CommonEnum.DELETE_NO.getValue());

        // 待添加的角色与系统接口关联对象列表
        List<RoleUriEntity> roleUriList = new ArrayList<>();
        // 待删除与角色关联的系统接口主键列表
        List<Long> removeUriIdList = new ArrayList<>();

        // 1、数据处理
        if (uriIdList.isEmpty()) {
            // 角色参数对象携带的系统接口主键列表为空
            removeUriIdList = new ArrayList<>(uriIdSet);
        } else if (uriIdSet.isEmpty()) {
            // 角色原来没有关联的系统接口
            for (Long uriId : uriIdList) {
                RoleUriEntity roleUri = this.getRoleUri(roleId, uriId, userPo, date);
                // 记录数据
                roleUriList.add(roleUri);
            }
        } else {
            // 角色新关联系统接口主键列表 和 角色已关联的系统接口主键集合 进行处理操作
            for (Long uriId : uriIdList) {
                /*
                    从系统接口主键集合中删除系统接口主键
                    1、删除成功，角色已关联该系统接口，无需操作
                    2、删除失败，角色未关联该系统接口，需要进行关联
                 */
                if (uriIdSet.remove(uriId)) {
                    // 已关联，无需操作
                    continue;
                }
                RoleUriEntity roleUri = this.getRoleUri(roleId, uriId, userPo, date);
                // 记录数据
                roleUriList.add(roleUri);
            }
        }
        // 2、剩余数据处理
        if (!uriIdSet.isEmpty()) {
            // 角色已关联系统接口主键集合不为空，则说明集合剩余的元素，角色已经取消关联，需要删除
            removeUriIdList = new ArrayList<>(uriIdSet);
        }
        // 3、处理结果入库
        if (!roleUriList.isEmpty()) {
            // 需要新关联的列表不为空
            log.info("角色关联系统接口");
            this.saveBatch(roleUriList);
        }
        if (!removeUriIdList.isEmpty()) {
            log.info("删除角色关联系统接口");
            this.deleteRoleUri(Collections.singletonList(roleId), removeUriIdList, userPo.getId());
        }
    }

    @Transactional
    @Override
    public void addOrModifyRoleUri(List<Long> roleIdList, Long uriId) {
        // 获取正在保存系统接口关联角色数据的用户
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        // 查询系统接口已关联的角色主键集合
        Set<Long> roleIdSet = baseMapper.findRoleIdSet(uriId, CommonEnum.DELETE_NO.getValue());

        // 待添加的角色与系统接口关联对象列表
        List<RoleUriEntity> roleUriList = new ArrayList<>();
        // 待删除与角色关联的系统接口主键列表
        List<Long> removeRoleIdList = new ArrayList<>();

        // 1、数据处理
        if (roleIdList.isEmpty()) {
            // 角色参数对象携带的角色主键列表为空
            removeRoleIdList = new ArrayList<>(roleIdSet);
        } else if (roleIdSet.isEmpty()) {
            // 系统接口原来没有关联的角色
            for (Long roleId : roleIdList) {
                RoleUriEntity roleUri = this.getRoleUri(roleId, uriId, userPo, date);
                // 记录数据
                roleUriList.add(roleUri);
            }
        } else {
            // 系统接口新关联角色主键列表 和 系统接口已关联的角色主键集合 进行处理操作
            for (Long roleId : roleIdList) {
                /*
                    从角色主键集合中删除角色主键
                    1、删除成功，系统接口已关联该角色，无需操作
                    2、删除失败，系统接口未关联该角色，需要进行关联
                 */
                if (roleIdSet.remove(roleId)) {
                    // 已关联，无需操作
                    continue;
                }
                RoleUriEntity roleUri = this.getRoleUri(roleId, uriId, userPo, date);
                // 记录数据
                roleUriList.add(roleUri);
            }
        }
        // 2、剩余数据处理
        if (!roleIdSet.isEmpty()) {
            // 系统接口已关联角色主键集合不为空，则说明集合剩余的元素，系统接口已经取消关联，需要删除
            removeRoleIdList = new ArrayList<>(roleIdSet);
        }
        // 3、处理结果入库
        if (!roleUriList.isEmpty()) {
            // 需要新关联的列表不为空
            log.info("系统接口关联角色");
            this.saveBatch(roleUriList);
        }
        if (!removeRoleIdList.isEmpty()) {
            log.info("删除系统接口关联角色");
            this.deleteRoleUri(removeRoleIdList, Collections.singletonList(uriId), userPo.getId());
        }
    }

    @Override
    public List<UriEntity> getSimpleUriList(Set<Long> roleIdSet) {
        return baseMapper.getSimpleUriList(roleIdSet, CommonEnum.DELETE_NO.getValue());
    }

    @Override
    public void deleteRoleUri(List<Long> roleIdList, List<Long> uriIdList) {
        // 获取正在删除角色关联’系统接口‘的用户主键
        Long userId = UserUtils.getUserId();

        this.deleteRoleUri(roleIdList, uriIdList, userId);
    }

    /**
     * 生成角色与系统接口实体对象
     * @param roleId 角色主键
     * @param uriId  系统接口主键
     * @return 角色与系统接口实体对象
     */
    private RoleUriEntity getRoleUri(Long roleId, Long uriId, UserPo userPo, Date date) {
        RoleUriEntity roleUri = new RoleUriEntity();
        roleUri.setId(snowflakeService.getId())
                .setRoleId(roleId)
                .setUriId(uriId)
                .setDeleteStatus(CommonEnum.DELETE_NO.getValue())
                .setDeleteTime(date)
                .setDeleteUserId(CommonEnum.DEFAULT_ID.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getId());
        return roleUri;
    }

    /**
     * 批量删除角色与系统接口关联关系操作
     * 根据角色主键和系统接口主键列表，批量取消角色与系统接口的关联关系
     * @param roleIdList 角色主键列表
     * @param uriIdList  系统接口主键列表
     * @param optUserId  操作用户
     */
    private void deleteRoleUri(List<Long> roleIdList, List<Long> uriIdList, Long optUserId) {

        LambdaUpdateWrapper<RoleUriEntity> roleUriLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置 删除状态、删除时间和操作删除的用户 字段
        roleUriLambdaUpdateWrapper.set(RoleUriEntity::getDeleteStatus, CommonEnum.DELETE_YES.getValue())
                .set(RoleUriEntity::getDeleteTime, new Date())
                .set(RoleUriEntity::getDeleteUserId, optUserId);
        // 匹配 角色主键、系统接口主键和删除状态 字段
        roleUriLambdaUpdateWrapper.in(!CollectionUtils.isEmpty(roleIdList), RoleUriEntity::getRoleId, roleIdList)
                .in(!CollectionUtils.isEmpty(uriIdList), RoleUriEntity::getUriId, uriIdList)
                .eq(RoleUriEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 删除角色与系统接口的关联关系
        int count = baseMapper.update(null, roleUriLambdaUpdateWrapper);
        log.info("批量删除角色与系统接口关联关系完成，成功删除{}条数据", count);
    }
}